package edu.gatech.cs2340.mule.view;

import javax.swing.*;
import javax.swing.event.ChangeListener;

import edu.gatech.cs2340.mule.model.Player;

import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.util.Collection;

/**
 * The frame that holds both the MapPanel and the PlayerInfoPanel. Will also
 * display the TownPanel when the Town is entered.
 * 
 * Main Frame for the game.
 * 
 * @author Zach Elliott
 */
public class MuleGameFrame extends JFrame {
	
	private MapPanel mapPanel;
	private PlayerInfoPanel infoPanel;
	private TownPanel townPanel;
	private BannerPanel bannerPanel;
	private StorePanel storePanel;
	private BuyPanel buyPanel;
	private SellPanel sellPanel;
	private MuleBuyingPanel muleBuyingPanel;
	private ScoreboardPanel scoreboardPanel;
	private BottomBannerPanel bottomBannerPanel;
	
	/**
	 * Creates each individual panel to be displayed within the frame
	 */
	public MuleGameFrame() {
		super();
		setLayout(new BorderLayout());
		mapPanel = new MapPanel();
		infoPanel = new PlayerInfoPanel();
		townPanel = new TownPanel();
		bannerPanel = new BannerPanel();
		storePanel = new StorePanel();
		buyPanel = new BuyPanel();
		sellPanel = new SellPanel();
		muleBuyingPanel = new MuleBuyingPanel();
		scoreboardPanel = new ScoreboardPanel();
		bottomBannerPanel = new BottomBannerPanel();
		
		add(mapPanel, BorderLayout.CENTER);
		add(infoPanel, BorderLayout.EAST);
		add(bannerPanel, BorderLayout.NORTH);
		add(scoreboardPanel, BorderLayout.WEST);
		add(bottomBannerPanel, BorderLayout.SOUTH);
	}
	
	/**
	 * Removes the pass button in PlayerInfoPanel
	 */
	public void removePass() {
		infoPanel.removePass();
	}
	
	/**
	 * Disables the map to make buttons unclickable
	 */
	public void disableMap() {
		mapPanel.disableMap();
	}
	
	/**
	 * Disables the map to make buttons unclickable
	 */
	public void enableMap() {
		mapPanel.enableMap();
	}
	
	/**
	 * Enables all specified buttons so that they can be clicked
	 */
	public void enableButtons(Collection<Point> mapTiles) {
		mapPanel.enableButtons(mapTiles);
	}
	
	/**
	 * Updates the time label in PlayerInfoPanel
	 * to display the current time left in the player's turn
	 * @param time
	 */
	public void updateTimeLabel(int time) {
		bannerPanel.updateTimeLabel(time);
	}
	
	/**
	 * Disables all specified buttons so that they cannot be clicked
	 */
	public void disableButtons(Collection<Point> mapTiles) {
		mapPanel.disableButtons(mapTiles);
	}
	
	/**
	 * Updates the righthand and upper panels to view information corresponding
	 * to the active player
	 * @param currentPlayer
	 * @param round current round of the game
	 */
	public void updatePlayerInfoPanel(Player currentPlayer, int round) {
		infoPanel.updatePlayerInfoPanel(currentPlayer);
		bannerPanel.updatePlayerLabel(currentPlayer);
		bannerPanel.updateRoundLabel(round);
	}
	
	/**
	 * Updates the righthand and upper panels to view information corresponding
	 * to the active player. Does not update the round label on BannerPanel
	 * @param currentPlayer
	 * @param round current round of the game
	 */
	public void updatePlayerInfoPanelDuringLandSelection(Player currentPlayer, int round) {
		infoPanel.updatePlayerInfoPanel(currentPlayer);
		bannerPanel.updatePlayerLabel(currentPlayer);
	}
	
	/**
	 * Receives imageSource and button location from the presenter and
	 * tells the appropriate panel to add the image to the corresponding
	 * button.
	 * @param i button's x coordinate on the grid
	 * @param j button's y coordinate on the grid
	 * @param imageSource
	 */
	public void addImageToButton(int i, int j, String imageSource) {
		mapPanel.addImageToButton(j, i, imageSource);
	}
	
	/**
	 * Adds the listener to all buttons in the MapPanel's grid
	 * @param a
	 */
	public void addListenersToGrid(ActionListener a) {
		mapPanel.addListenersToGrid(a);
	}
	
	/**
	 * Adds the listener to the exit buttons in the TownPanel's grid
	 * @param a
	 */
	public void addExitListener(ActionListener a) {
		townPanel.addExitListener(a);
	}
	
	/**
	 * Adds the listener to the exit buttons in the TownPanel's grid
	 * @param a
	 */
	public void addStoreListener(ActionListener a) {
		townPanel.addStoreListener(a);
	}
	
	/**
	 * Adds the listener to the exit buttons in the TownPanel's grid
	 * @param a
	 */
	public void addPubListener(ActionListener a) {
		townPanel.addPubListener(a);
	}
	
	/**
	 * Adds the listener to the exit buttons in the TownPanel's grid
	 * @param a
	 */
	public void addLandOfficeListener(ActionListener a) {
		townPanel.addLandOfficeListener(a);
	}
	
	/**
	 * Adds the listener to the pass buttons in PlayerInfoPanel
	 * @param a
	 */
	public void addPassListener(ActionListener a) {
		infoPanel.addPassListener(a);
	}
	
	/**
	 * Adds the listener to the save buttons in PlayerInfoPanel
	 * @param a
	 */
	public void addSaveListener(ActionListener a) {
		infoPanel.addSaveListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the buy button
	 * in the store panel
	 */
	public void addBuyListener(ActionListener a) {
		storePanel.addBuyListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the sell button
	 * in the store panel
	 */
	public void addSellListener(ActionListener a) {
		storePanel.addSellListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the purchase mule button
	 * in the store panel
	 */
	public void addBuyMuleListener(ActionListener a) {
		storePanel.addPurchaseMuleListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the exit button
	 * in the store panel
	 */
	public void addStoreExitListener(ActionListener a) {
		storePanel.addExitListener(a);
	}
	
	/**
	 * 
	 * @param c the change listener to be added to the spinner
	 * in the buy panel
	 */
	public void addBuyPanelSpinnerListener(ChangeListener c) {
		buyPanel.addSpinnerListener(c);
	}
	
	/**
	 * 
	 * @param c the change listener to be added to the spinner
	 * in the sell panel
	 */
	public void addSellPanelSpinnerListener(ChangeListener c) {
		sellPanel.addSpinnerListener(c);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the buy button
	 * in the buy panel
	 */
	public void addBuyPanelBuyListener(ActionListener a) {
		buyPanel.addBuyListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the cancel button
	 * in the buy panel
	 */
	public void addBuyPanelCancelListener(ActionListener a) {
		buyPanel.addCancelListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the sell button
	 * in the sell panel
	 */
	public void addSellPanelSellListener(ActionListener a) {
		sellPanel.addSellListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the cancel button
	 * in the sell panel
	 */
	public void addSellPanelCancelListener(ActionListener a) {
		sellPanel.addCancelListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the buy button
	 * in the mule buying panel
	 */
	public void addMulePanelBuyListener(ActionListener a) {
		muleBuyingPanel.addBuyListener(a);
	}
	
	/**
	 * 
	 * @param a the action listener to be added to the cancel button
	 * in the mule buying panel
	 */
	public void addMulePanelCancelListener(ActionListener a) {
		muleBuyingPanel.addCancelListener(a);
	}
	
	/**
	 * 
	 * @param i the item listener to be added to the combo box
	 * in the mule buying panel
	 */
	public void addMulePanelComboListener(ItemListener i) {
		muleBuyingPanel.addComboListener(i);
	}
	
	/**
	 * 
	 * @param i the item listener to be added to the combo box
	 * in the buy panel
	 */
	public void addBuyPanelComboListener(ItemListener i) {
		buyPanel.addComboListener(i);
	}
	
	/**
	 * 
	 * @param i the item listener to be added to the combo box
	 * in the sell panel
	 */
	public void addSellPanelComboListener(ItemListener i) {
		sellPanel.addComboListener(i);
	}
	
	/**
	 * Updates the price label in the buy panel based on the price of
	 * the current transaction
	 * @param price
	 */
	public void updateBuyPanelPriceLabel(int price) {
		buyPanel.updateBuyPanelPriceLabel(price);
	}
	
	/**
	 * Updates the price label in the sell panel based on the price of
	 * the current transaction
	 * @param price
	 */
	public void updateSellPanelPriceLabel(int price) {
		sellPanel.updateSellPanelPriceLabel(price);
	}
	
	/**
	 * Updates the maximum value allowed in the spinner in the buy panel
	 * based on the stores stock
	 * @param amount
	 */
	public void updateBuyPanelSpinnerMax(int amount) {
		buyPanel.updateBuyPanelSpinnerMax(amount);
	}
	
	/**
	 * Updates the maximum value allowed in the spinner in the sell panel
	 * based on the current player's amount owned
	 * @param amount
	 */
	public void updateSellPanelSpinnerMax(int amount) {
		sellPanel.updateSellPanelSpinnerMax(amount);
	}
	
	/**
	 * Updates the price label in the mule buying panel based on the price of
	 * the current transaction
	 * @param price
	 */
	public void updateMulePriceLabel(int price) {
		muleBuyingPanel.updatelPriceLabel(price);
	}
	
	/**
	 * Recolors the price label in the buy panel
	 */
	public void recolorPriceLabel() {
		buyPanel.recolorPriceLabel();
	}
	
	/**
	 * Recolors the price label in the mule buying panel
	 */
	public void setMulePriceLabelColor() {
		muleBuyingPanel.setPriceLabelColor();
	}
	
	/**
	 * Finds the button's x and y coordinate on the grid.
	 * @param button
	 * @return
	 */
	public Point getButtonPoint(JButton button) {
		return mapPanel.getButtonPoint(button);
	}
	
	/**
	 * 
	 * @return the resource type selected by the combo box in the buy panel
	 */
	public String getSelectedResourceToBuy() {
		return buyPanel.getSelectedResource();
	}
	
	/**
	 * 
	 * @return the resource amount selected by the spinner in the buy panel
	 */
	public int getSelectedAmountToBuy() {
		return buyPanel.getSelectedAmount();
	}
	
	/**
	 * 
	 * @return the resource type selected by the combo box in the sell panel
	 */
	public String getSelectedResourceToSell() {
		return sellPanel.getSelectedResource();
	}
	
	/**
	 * 
	 * @return the resource amount selected by the spinner in the sell panel
	 */
	public int getSelectedAmountToSell() {
		return sellPanel.getSelectedAmount();
	}
	
	/**
	 * Updates the button's whose coordinates are specified by the point
	 * border based on the currentPlayer's chosen color.
	 * @param p
	 * @param currentPlayer
	 */
	public void updateButtonColor(Point p, Player currentPlayer) {
		mapPanel.updateButtonColor(p, currentPlayer);
	}
	
	/**
	 * Changes panel focus from the map to the town.
	 */
	public void enterTown() {
		remove(mapPanel);
		add(townPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the town to the store.
	 */
	public void enterStore() {
		remove(townPanel);
		add(storePanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the town to the map.
	 */
	public void exitTown() {
		remove(townPanel);
		add(mapPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the store to the town.
	 */
	public void exitStore() {
		remove(storePanel);
		add(townPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the store to the buying panel.
	 */
	public void enterBuyPanel() {
		remove(storePanel);
		add(buyPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the store to the selling panel.
	 */
	public void enterSellPanel() {
		remove(storePanel);
		add(sellPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the store to the mule buying panel.
	 */
	public void enterMuleBuyingPanel() {
		remove(storePanel);
		add(muleBuyingPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the buying panel to the store.
	 */
	public void moveFromBuyToStore() {
		remove(buyPanel);
		add(storePanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the selling panel to the store.
	 */
	public void moveFromSellToStore() {
		remove(sellPanel);
		add(storePanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the mule buying panel to the store.
	 */
	public void moveFromMuleToStore() {
		remove(muleBuyingPanel);
		add(storePanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the mule buying panel to the map.
	 */
	public void moveFromMuleBuyingToMap() {
		remove(muleBuyingPanel);
		add(mapPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from the map to the mule buying panel.
	 */
	public void moveFromMapToMuleBuying() {
		remove(mapPanel);
		add(muleBuyingPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Changes focus from all panels to the town.
	 */
	public void moveToTown() {
		remove(muleBuyingPanel);
		remove(sellPanel);
		remove(buyPanel);
		remove(storePanel);
		remove(mapPanel);
		add(townPanel, BorderLayout.CENTER);
		repaint();
		setSize(1201,700);
		setSize(1200,700);
	}
	
	/**
	 * Adds the round label to the banner panel
	 */
	public void addRoundLabel() {
		bannerPanel.addRoundLabel();
	}

	/**
	 * 
	 * @return the mule type selected by the user via the combo box
	 * in the mule buying panel
	 */
	public int getSelectedMuleType() {
		return muleBuyingPanel.getSelectedMuleType();
	}
	
	/**
	 * Updates the scoreboard panel with the current list of players
	 * @param players
	 */
	public void updateScoreboard(Player[] players) {
		scoreboardPanel.updateScoreboard(players);
	}
	
	/**
	 * Updates the production panel with the current production and player
	 * @param production
	 * @param currentPlayer
	 */
	public void updateProductionPanel(int[] production, int currentPlayer) {
		scoreboardPanel.updateProductionPanel(production, currentPlayer);
	}
	
	/**
	 * Colors the production panel based on the chosen colors of the players
	 * @param players
	 */
	public void colorProductionPanel(Player[] players) {
		scoreboardPanel.colorProductionPanel(players);
	}
	
	/**
	 * Displays the specified message on the bottom of the screen
	 * @param message the String to be displayed to the user
	 */
	public void updateBottomBannerPanel(String message) {
		bottomBannerPanel.updateBottomBannerLabel(message);
	}
}
